import random
import hashlib

from server.database.user import get_user_all_profile_by_user_id
from sts import Sts
from collections import defaultdict
from sqlalchemy.orm import Session
from log import logger
from config import cos_client, COS_Bucket, sts_config, COS_CONFIG
from server.models.achievement import SubmittedForm, SubmittedFormContent, AchievementRule
from server.schemas.review import SubmittedFormUserCreate, SubmittedFormQuery, SubmittedReview
from server.controllers.achievement import get_achievement_rules_by_achievement_id, get_achievement_and_info_by_id
from server.database.achievement import query_all_achievements
from server.database.review import *
from server.database import redis_db
from utils import ProjectException, object_to_dict
import datetime



def get_achievement_list(session: Session, user_id=None):
    """获取发布成果表列表"""
    achievements = query_all_achievements(session)
    if user_id is None:
        result = [object_to_dict(item) for item in achievements]
        return result
    submitted_forms = query_submitted_form_by_user_id(session, user_id)
    result = []
    for achievement in achievements:
        if achievement.status != 'publish':
            continue
        row = object_to_dict(achievement)
        # 检查成就ID是否在已提交的ID集合中
        row["submitted_form"] = None
        for submitted_form in submitted_forms:
            if submitted_form.achievement_id == achievement.id:
                row["submitted_form"] = object_to_dict(submitted_form)
                break
        result.append(row)
    result.reverse()
    return result



def convert_achievement_rule_format(data):
    # 目标数据结构
    output = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))

    # 构造嵌套结构
    for item in data:
        primary = item["primary_subject"]
        secondary = item["secondary_subject"]
        tertiary = {
            "id": item["id"],
            "name": item["tertiary_subject"],
            "level": item["level"],
            "text_info": item["text_info"],
            "requires_file": item["requires_file"],
            "score": item["score"]
        }
        output[primary][secondary]["tertiary_subjects"].append(tertiary)

    # 将defaultdict转换为普通dict
    def defaultdict_to_dict(d):
        if isinstance(d, defaultdict):
            d = {k: defaultdict_to_dict(v) for k, v in d.items()}
        return d

    output_dict = defaultdict_to_dict(output)

    # 构造最终结果
    final_result = {
        "primary_subjects": [
            {
                "name": primary,
                "secondary_subjects": [
                    {
                        "name": secondary,
                        "tertiary_subjects": tertiary_list["tertiary_subjects"]
                    }
                    for secondary, tertiary_list in secondary_dict.items()
                ]
            }
            for primary, secondary_dict in output_dict.items()
        ]
    }

    return final_result


def get_achievement_info_and_rules(session: Session, achievement_id: int):
    result = defaultdict()
    achievement_rules = get_achievement_rules_by_achievement_id(session, achievement_id)
    achievement_info = get_achievement_and_info_by_id(session, achievement_id)
    for key in ['id', 'title', 'description', 'publish_time', 'status']:
        result[key] = achievement_info.get(key)
    result.update(convert_achievement_rule_format(achievement_rules))
    return result


def get_upload_sign(file_name):
    """
    获取文件上传签名url，文件名为日期+随机md5+后缀
    :param file_name: 文件名
    :return: 签名，新文件名
    """
    # 获取文件名后缀
    file_suffix = file_name.split('.')[-1] if '.' in file_name else ''

    # 获取当前日期，格式为 YYYYMMDD
    current_date = datetime.datetime.now().strftime('%Y%m%d')

    # 生成随机MD5值
    random_md5 = hashlib.md5(str(random.random()).encode()).hexdigest()

    # 生成新的文件名：日期+随机md5+后缀
    new_file_name = f"{current_date}_{random_md5}.{file_suffix}" if file_suffix else f"{current_date}_{random_md5}"

    # 生成上传 URL，未限制请求头部和请求参数

    sts = Sts(sts_config)
    data = sts.get_credential()
    data.update(dict(
        file_name=new_file_name,
        key=f"files/{new_file_name}",
        bucket=sts_config.get('bucket'),
        region=sts_config.get('region'),
    ))
    return data


def get_download_sign(file_name) -> str:
    """
    获取文件下载签名url
    :param file_name: 文件名
    :return: 签名
    """
    url = cos_client.get_presigned_url(
        Method='GET',
        Bucket=COS_Bucket,
        Key=f'files/{file_name}',
        Expired=600  # 过期时间
    )
    return url


def create_submitted_form(db: Session, form_data: SubmittedFormUserCreate, user_id: int) -> SubmittedForm:
    """
    将成果提交上传至数据库
    """
    # 首先创建一个新的SubmittedForm记录
    new_form = SubmittedForm(
        achievement_id=form_data.achievement_id,
        user_id=user_id,  # 假设user_id由调用方提供
        submission_date=datetime.datetime.now(),
        total_score=0.0  # 初始总分为0
    )
    db.add(new_form)
    db.commit()
    db.refresh(new_form)

    # 使用新创建的submitted_form_id将内容添加到SubmittedFormContent
    for content_data in form_data.contents:
        new_content = SubmittedFormContent(
            submitted_form_id=new_form.id,
            form_rule_id=content_data.form_rule_id,
            text_info=content_data.text_info,
            file_link=content_data.file_link,
            review_status='pending',  # 默认状态
            score=0.0  # 初始分数为0
        )
        db.add(new_content)

    db.commit()  # 最后提交所有新内容记录
    return new_form


def get_user_submitted_form_contents_by_achievement_id(db: Session, achievement_id: int, user_id: int) -> list[dict]:
    """获取与指定 user_id 和 achievement_id 关联的所有 SubmittedForm"""
    forms = query_submitted_form_by_achievement_and_user(db, achievement_id, user_id)

    # 获取所有关联的 SubmittedFormContent，并关联 AchievementRule
    contents = []
    for form in forms:
        query = db.query(
            SubmittedFormContent,
            AchievementRule
        ).join(
            AchievementRule, SubmittedFormContent.form_rule_id == AchievementRule.id
        ).filter(
            SubmittedFormContent.submitted_form_id == form.id
        )

        for content, rule in query.all():
            merged_content = {
                "submitted_form_content": object_to_dict(content),
                "form_rule": object_to_dict(rule)
            }
            contents.append(merged_content)

    return contents


def lock_record(record_id: int, auditor_id: int) -> bool:
    """锁定成果，如果已经锁定返回False"""
    lock_key = f"lock:{record_id}"
    existing_auditor_id = redis_db.get(lock_key)
    if existing_auditor_id is not None and int(existing_auditor_id) != auditor_id:
        # 已经被锁定且不是当前用户锁定
        return False

    # 设置锁并设置过期时间（5分钟）
    redis_db.set(lock_key, auditor_id, ex=300)
    logger.debug(f"lock record {record_id} by {auditor_id}")
    return True


def unlock_record(record_id):
    """解除锁定"""
    lock_key = f"lock:{record_id}"
    redis_db.delete(lock_key)
    logger.debug(f"Unlocked record {record_id}")


def get_submitted_form_and_info(db: Session, params: SubmittedFormQuery):
    """查询SubmittedForm表以及对应的用户信息"""
    # 检查 page 和 length 参数的合法性
    if params.page < 1:
        raise ProjectException("页数必须大于或等于1")
    if params.length < 1:
        raise ProjectException("每页条目数必须大于或等于1")

    # 获取数据总数
    total_count = query_submitted_form_total_count(db, params.id, params.status)

    # 分页查询数据
    forms = query_submitted_form_by_achievement_id(db, params.id, params.status, params.length, params.page)
    result = []
    for form in forms:
        item = object_to_dict(form)
        item.update({'user_profile': object_to_dict(form.user.profile)})
        if form.user.profile:
            item['user_profile'].update({'class': object_to_dict(form.user.profile.student_class)})
        result.append(item)

    return {"total_count": total_count, "forms": result}


def select_submitted_form_by_id(db: Session, submitted_form_id: int, user_id: int):
    """选定指定submitted_form并获取指定信息"""
    if not lock_record(record_id=submitted_form_id, auditor_id=user_id):
        raise ProjectException("该成果已被锁定，请稍后尝试")
    submitted_form = query_submitted_form_and_contents(db, submitted_form_id)
    if submitted_form is None:
        raise ProjectException("该成果不存在，请检查id")
    result = object_to_dict(submitted_form)
    submitted_form_contents = []
    if submitted_form.contents:
        for content in submitted_form.contents:
            content_dict = object_to_dict(content)
            content_dict['form_rule'] = object_to_dict(content.form_rule)
            content_dict['reviews'] = object_to_dict(content.reviews[0] if content.reviews else None)
            submitted_form_contents.append(content_dict)
        result['contents'] = submitted_form_contents
    result['user'] = get_user_all_profile_by_user_id(db, submitted_form.user_id)
    result['achievement'] = object_to_dict(submitted_form.achievement)
    result['file_server'] = f'https://{COS_CONFIG["bucket"]}.cos.{COS_CONFIG["region"]}.myqcloud.com/files/'
    return result


def submit_review(db: Session, params: SubmittedReview, user_id: int):
    """提交审核内容"""
    update_review_status_and_add_review(
        db=db,
        submitted_form_content_id=params.id,  # 需要审核的内容ID
        reviewer_id=user_id,  # 审核者ID
        review_comments=params.comment,  # 审核意见
        review_status=params.type  # 是否通过
    )

